package utils

import (

	"os"

	"sync"
	"errors"

	"encoding/hex"
	"fmt"
	"log"
	"bufio"
	"os/exec"
	"path/filepath"


	"cert/pkg/alg"
)

type UpgradeCtx struct {
	sign    []byte
	payload string		// 被签名的载体
	pubFile string
	keyFile string
	input   string
	dir     string
	output  string
	temp    string
	workdir string
	status  string
	lastlog string		// 最后一次升级的日志
	mutex  *sync.Mutex
}

func Run(cmd string) bool{
	log.Printf("执行 %s\n", cmd)
	ctx := exec.Command("bash", "-c", cmd)
	// 获取命令的输出管道
	stdoutPipe, err := ctx.StdoutPipe()
	if err != nil {
		log.Printf("ctx.StdoutPipe : %v\n", err)
		return false
	}
	ctx.Stderr = ctx.Stdout
	// 开始命令
	if err := ctx.Start(); err != nil {
		log.Printf("ctx.Start : %v\n", err)
		return false
	}
	reader := bufio.NewReader(stdoutPipe)
	for {
		line, err := reader.ReadString('\n')
		if err != nil {
			break // 读取完毕或发生错误
		}
		log.Print(line)
	}

	// 等待命令执行完毕
	if err := ctx.Wait(); err != nil {
		log.Printf("升级失败 : %v\n", err)
		return false
	}
	return true
}

func (self *UpgradeCtx) Init(input, output, pubFile, keyFile string) *UpgradeCtx{
	self.input      = input
	self.output     = output
	self.pubFile    = pubFile
	self.keyFile    = keyFile

	self.workdir,_  = os.MkdirTemp("", "olym.")
	self.temp       = filepath.Join(self.workdir, "olym.tgz")
	self.lastlog    = "/opt/upgrade-service/logs/last.log"
	self.mutex      = &sync.Mutex{}

	return self
}


func (self *UpgradeCtx) Sign(files ...string) *UpgradeCtx {

	if len(files) > 0 {
		// 获取第一个参数
		self.temp = files[0]
	}
	data, err := os.ReadFile(self.temp)
	if err != nil {
		return self
	}
	sm2Ctx, err := alg.NewSM2KeyContext( alg.WithSM2X509Key(self.keyFile))
	if err != nil {
		panic(err)
		return self
	}
	sign,err := sm2Ctx.Sign(data)
	log.Printf("%v", hex.EncodeToString(sign))
	self.sign = sign
	return self
}

// 这个提取出来，不能加锁
func (self *UpgradeCtx) do_verify(pack string) error {

	data, err := os.ReadFile(pack)
	if err != nil {
		log.Printf("[Verify] os.ReadFile %v", err)
		return err
	}
	sign2Ctx, err := alg.NewSM2KeyContext( alg.WithSM2PEMCertFile(self.pubFile))
	if err != nil {
		log.Printf("[Verify] alg.NewSM2KeyContext %v", err)
		return err
	}
	self.sign,_ = hex.DecodeString(self.keyFile)
	ret := sign2Ctx.Verify(data, self.sign)
	log.Printf("Verify=%v\n", ret)
	if !ret {
		return errors.New("签名校验失败")
	}
	return nil
}

func (self *UpgradeCtx) Verify(files ...string) error {

	locked := self.mutex.TryLock()
	if !locked {
		// 无法立即获取锁
		return errors.New(fmt.Sprintf("其他升级任务正在执行 [%s]", self.status))
	}
	defer self.mutex.Unlock()

	// self.Verifying()
	// defer self.Finished()

	if len(files) > 0 {
		// 获取第一个参数
		self.input = files[0]
	}
	return self.do_verify(self.input)
}
